package coalition.formation.parse;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.List;

import coalition.formation.partitions.PartitionDecorator;


public class PartitionParser {
	
	int numAgents;
	
	public PartitionParser(String fileName){
		this.fileName = fileName;
	}
	
	public static void main(String[] args) {

		
	}
	
	StreamTokenizer st;
	FileInputStream file;
	String fileName;

	
	public List<PartitionPlusExternalities> analyze() throws FileNotFoundException {
		
		List<PartitionPlusExternalities> partitionsList =
			new ArrayList<PartitionPlusExternalities>();
		
		List<List<Integer>> partitionList;
		
		try {
			file = new FileInputStream(fileName);

			Reader r = new BufferedReader(new InputStreamReader(file));
			st = new StreamTokenizer(r);

			st.parseNumbers();
			st.eolIsSignificant(true);
			st.slashSlashComments(true);
		} catch(FileNotFoundException fnfe) {
			System.out.println(
					"Could not open " + file);
			throw fnfe;
		}
	    
	    //get the number of agents
	    int numAgents = getInteger();
	    //System.out.println("got num Agents: " + numAgents);
	    getEOL();

	    while(true){//for each line in the file
	    	partitionList = new ArrayList<List<Integer>>();
		    
	    	//starting a new line
	    	//skip blank lines
	    	while(getEOL()){}
	    	
			if(getEOF()){
				break;
			}
	    	
	    	List<Float> externalitiesList;
	    	
		    //parse the partition
				
			//look for the partition bracket
			getLeftCurly();
			//System.out.println("\tgot partition left curly");
			while(true){
				//look for a coalition bracket
				getLeftCurly();
				//System.out.println("\t\tgot coalition left curly");
				List<Integer> list = new ArrayList<Integer>();
				while(true){
					//get the agents in the coalition
					int index = getInteger();
					//System.out.println("\t\t\tgot partition index: " + index);
					list.add(index);
					if(!getComma()){
						break;
					}
					//System.out.println("\t\tgot coalition comma");
				}
				partitionList.add(list);
				getRightCurly();
				//System.out.println("\t\tgot coalition right curly");
				
				if(!getComma()){
					//System.out.println("\tno partition comma");
					st.pushBack();
					break;
				}
				//System.out.println("\tgot partition comma");
			}
			getRightCurly();
			//System.out.println("\tgot partition right curly");
				
			
			//getComma();
			//System.out.println("\t\tgot partition-externalities comma");
			
			//parse the externalities
			externalitiesList = new ArrayList<Float>();
			
			getLeftCurly();
			//System.out.println("\tGot externality left curly");
			while(true){
				float externality = getFloat();
				//System.out.println("\tgot externality index: " + index);
				externalitiesList.add(externality);
				if(!getComma()){
					st.pushBack();
					break;
				}
				//System.out.println("\t\tgot externality comma");
			}			
			getRightCurly();
			//System.out.println("\tGot externality right curly");
			
			float[] externalitiesArray = new float[numAgents];
			int counter = 0;
			for(float f : externalitiesList){
				externalitiesArray[counter] = f;
				counter++;
			}
			
		    int[] partition = PartitionDecorator.convertFromListForm(partitionList, numAgents);
			
			PartitionPlusExternalities partitionPlusExternalities = 
				new PartitionPlusExternalities(partition, externalitiesArray);				
			
			partitionsList.add(partitionPlusExternalities);			
			
			if(getEOF()){
				break;
			}
			
			getEOL();
		
	    }
	    

		return partitionsList;
	}
	
	boolean getLeftCurly(){
		String leftCurly = getString();
		if(!leftCurly.equals("{") )
			return false;
		return true;
	}
	
	boolean getComma(){
		String comma = getString();
		if(!comma.equals(",") ){
			st.pushBack();
			return false;
		}
		return true;
	}	
	
	boolean getRightCurly(){
		String rightCurly = getString();
		if(!rightCurly.equals("}") )
			return false;
		return true;
	}	
	
	String getString(){
		int tokenType;
		try{
			tokenType = st.nextToken();
		} catch (IOException ioe){
			System.out.println("error in getString: " + ioe);
			throw new IllegalStateException();
		}
		//if (st.ttype != StreamTokenizer.TT_WORD){
		
		//System.out.println("got string: |" + (char)st.ttype + "|");
		return "" + (char)st.ttype;
	}
	
	int getInteger(){
		try{
			int tokenType = st.nextToken();
		} catch (IOException ioe){
			System.out.println("error in getInteger: " + ioe);
		}
		if (st.ttype != StreamTokenizer.TT_NUMBER)
			throw new IllegalStateException();
		//System.out.println("got integer: " + (int)st.nval);
		return (int)st.nval;
	}	
	
	float getFloat(){
		try{
			float tokenType = st.nextToken();
		} catch (IOException ioe){
			System.out.println("error in getInteger: " + ioe);
		}
		if (st.ttype != StreamTokenizer.TT_NUMBER)
			throw new IllegalStateException();
		//System.out.println("got integer: " + (int)st.nval);
		return (float)st.nval;
	}		
	
	boolean getEOF(){
		try{
			int tokenType = st.nextToken();
		} catch (IOException ioe){
			System.out.println("error in isEOF: " + ioe);
		}
		if (st.ttype == StreamTokenizer.TT_EOF)
			return true;
		else{
			st.pushBack();
			return false;
		}
	}	
	
	boolean getEOL(){
		try{
			int tokenType = st.nextToken();
		} catch (IOException ioe){
			System.out.println("error in isEOL: " + ioe);
		}
		if (st.ttype == StreamTokenizer.TT_EOL)
			return true;
		else{
			st.pushBack();
			return false;
		}

	}		
	
	static void prt(String s) {
		System.out.println(s);
	}
}

